﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MovieRental.Entities;
using MovieRental.DataInterfaces;
using MovieRental.BuisnessComponents.Base;
using MovieRental.BuisnessComponents.Exceptions;
using MovieRental.BuisnessComponents.Helpers;

namespace MovieRental.BuisnessComponents
{
    public class PersonalDiscountComponent : BaseSetComponent<PersonalDiscountInfo, Guid, IPersonalDiscountRepository>
    {
        public PersonalDiscountComponent(IPersonalDiscountRepository repository)
            : base(repository)
        {
        }

        protected override bool Equals(PersonalDiscountInfo obj1, PersonalDiscountInfo obj2)
        {
            return (obj1.SpentMoneyCondition == obj2.SpentMoneyCondition);
        }

        public override void Verify(PersonalDiscountInfo obj)
        {
            base.Verify(obj);
            if (obj.SpentMoneyCondition < 0)
                throw new FieldValueRangeException<double>(obj, "MoneySpentCondition", 0, double.MaxValue);
            ValueBound<double> bounds = GetValueBoundsForCondition(obj.SpentMoneyCondition);
            if (!bounds.IsInBounds(obj.Value))
                throw new FieldValueRangeException<double>(obj, "Value", bounds.Lower, bounds.Upper);
        }

        public override IEnumerable<PersonalDiscountInfo> GetAll()
        {
            return base.GetAll().OrderBy(x => x.SpentMoneyCondition);
        }

        public PersonalDiscountInfo AddDiscountRule(double spentMoneyCondition, double discountValue)
        {
            PersonalDiscountInfo discount = new PersonalDiscountInfo();
            discount.SpentMoneyCondition = spentMoneyCondition;
            discount.Value = discountValue;
            try
            {
                AddOrUpdate(discount);
            }
            catch (ItemDuplicateException<Guid> ex)
            {
                var duplicate = (PersonalDiscountInfo)ex.DuplicateObject;
                duplicate.Value = discountValue;
                AddOrUpdate(duplicate);
            }
            return discount;
        }

        public PersonalDiscountInfo GetAvailablePersonalDiscount(Guid customerId)
        {
            var loanCartComponent = ComponentFactory.Instance.GetLoanCartComponent();
            return GetAll().Where(x => x.SpentMoneyCondition < loanCartComponent.CountSpentMoney(customerId)).
                OrderBy(x => x.SpentMoneyCondition).LastOrDefault();
        }

        public ValueBound<double> GetValueBoundsForCondition(double spentMoney)
        {
            double lower, upper;
            var lowerDiscounts = Repository.LoadAll().Where(x => x.SpentMoneyCondition < spentMoney).OrderBy(x => x.SpentMoneyCondition);
            if (!lowerDiscounts.Any())
                lower = 0;
            else
                lower = lowerDiscounts.Last().Value;
            var upperDiscounts = Repository.LoadAll().Where(x => x.SpentMoneyCondition > spentMoney).OrderBy(x => x.SpentMoneyCondition);
            if (!upperDiscounts.Any())
                upper = 100.0;
            else
                upper = upperDiscounts.First().Value;
            return new ValueBound<double>(lower, upper);
        }

        public double GetAvailablePersonalDiscountValue(Guid customerId)
        {
            var personalDiscount = GetAvailablePersonalDiscount(customerId);
            if (personalDiscount == null)
                return 0;
            return personalDiscount.Value;
        }
        
    }
}
